package com.gac.wms.workflow.custom;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.task.Task;
import org.springframework.security.core.context.SecurityContextHolder;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class RejectTaskBack implements Command<Void> {
    private String taskId;
    private String rejectReason;
    private Map<String, Object> variables;

    public RejectTaskBack(String taskId, Map<String, Object> variables, String rejectReason) {
        this.taskId = taskId;
        this.variables = variables;
        this.rejectReason = rejectReason;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        HistoryService historyService = ApplicationContextHandler.getBean(HistoryService.class);
        RepositoryService repositoryService = ApplicationContextHandler.getBean(RepositoryService.class);
        RuntimeService runtimeService = ApplicationContextHandler.getBean(RuntimeService.class);
        TaskService taskService = ApplicationContextHandler.getBean(TaskService.class);
        TaskRuntime taskRuntime = ApplicationContextHandler.getBean(TaskRuntime.class);
        TaskEntity task = commandContext.getTaskEntityManager().findById(taskId);
        if(StringUtils.isBlank(task.getAssignee())){
            // 领取任务
            taskService.claim(taskId, SecurityContextHolder.getContext().getAuthentication().getName());
        }
        String processInstanceId = task.getProcessInstanceId();
        List<HistoricTaskInstance> htiList = getHistoricTaskInstances(historyService, processInstanceId);
        if (htiList == null) return null;
        // list里的第二条代表上一个任务
        //HistoricTaskInstance lastTask = htiList.get(1);
        HistoricTaskInstance lastTask = htiList.get(htiList.size()-1);
        // list里第一条代表当前任务
        HistoricTaskInstance curTask = htiList.get(0);
        // 当前节点的executionId
        String curExecutionId = curTask.getExecutionId();
        // 上个节点的taskId
        String lastTaskId = lastTask.getId();
        // 上个节点的executionId
        String lastExecutionId = lastTask.getExecutionId();
        if (null == lastTaskId) {
            log.info("LAST TASK IS NULL");
        }
        String processDefinitionId = lastTask.getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        String lastActivityId = null;
        lastActivityId = getLastActivitiIdString(historyService, lastTaskId, lastExecutionId, lastActivityId);
        // 得到上个节点的信息
        FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivityId);
        // 取得当前节点的信息
        Execution execution = runtimeService.createExecutionQuery().executionId(curExecutionId).singleResult();
        String curActivityId = execution.getActivityId();
        FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curActivityId);
        //记录当前节点的原活动方向
        List oriSequenceFlows = new ArrayList<>();
        oriSequenceFlows.addAll(curFlowNode.getOutgoingFlows());
        //清理活动方向
        curFlowNode.getOutgoingFlows().clear();
        //建立新方向
        List newSequenceFlowList = new ArrayList<>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(curFlowNode);
        newSequenceFlow.setTargetFlowElement(lastFlowNode);
        newSequenceFlowList.add(newSequenceFlow);
        curFlowNode.setOutgoingFlows(newSequenceFlowList);
        // 完成任务
//        taskService.complete(taskId,variables);
        taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskId)
                .withVariables(variables)
                .build());
        //恢复原方向
        curFlowNode.setOutgoingFlows(oriSequenceFlows);
        Task nextTask = taskService
                .createTaskQuery().processInstanceId(processInstanceId).singleResult();
        // 设置执行人
        if(nextTask!=null) {
            taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
        }
        return null;
    }

    private String getLastActivitiIdString(HistoryService historyService, String lastTaskId, String lastExecutionId, String lastActivityId) {
        List<HistoricActivityInstance> haiFinishedList = historyService.createHistoricActivityInstanceQuery()
                .executionId(lastExecutionId).finished().list();
        for (HistoricActivityInstance hai : haiFinishedList) {
            if (lastTaskId.equals(hai.getTaskId())) {
                // 得到ActivityId，只有HistoricActivityInstance对象里才有此方法
                lastActivityId = hai.getActivityId();
                break;
            }
        }
        return lastActivityId;
    }

    private List<HistoricTaskInstance> getHistoricTaskInstances(HistoryService historyService, String processInstanceId) {
        // 取得所有历史任务按时间降序排序
        List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByTaskCreateTime()
                .desc()
                .list();
        if (ObjectUtils.isEmpty(htiList) || htiList.size() < 2) {
            return null;
        }
        return htiList;
    }
}
